# Usage: 
# Set up in $profile - define the functions and reassign 'cd'.  Example:
# -----
#  . .\Set-LocationEx.ps1 "c:\dev\Code", "c:\dev\Code\releases", "$HOME" -Verbose
# if (test-path alias:cd) { remove-item alias:cd > $null }
# Set-Alias cd Set-LocationEx
# -----

param( [parameter(Mandatory = $true)][string[]]$roots )

Set-StrictMode -Version Latest

Write-Verbose "Set-LocationEx roots: $(Join-String -Strings $roots -Separator ', ')"

function Set-LocationEx
{
	param( [Parameter( Mandatory="true" )]$path )

	process
	{ 
		$verbose = ( $PSCmdlet.MyInvocation.BoundParameters.ContainsKey( "Verbose" ) -and $PSCmdlet.MyInvocation.BoundParameters[ "Verbose" ].IsPresent )
		if ( $verbose )
			{ Write-Verbose( "$(Join-String -Strings $roots -Separator ', ')" ) }
		if ( !( Test-Path $path ) ) 
		{
			foreach ( $p in $roots )
			{ 
				$newPath = Join-Path $p $path
				if ( $verbose ) { Write-Verbose "Looking for $newPath" }
				if ( Test-Path $newPath ) 
				{ 
					$newPath = Get-PathCanonicalCase( $newPath )
					if ( $verbose ) { Write-Verbose "Found $newPath" }
					Push-Location $newPath
					return
				} 
			}
		}
		if ( Test-Path $path )
			{ $path = Get-PathCanonicalCase( $path ) }
		Push-Location $path
	}
}

function Get-LocationExRoots
{
	process
	{
		Write-Output (Join-String -Strings $roots -NewLine)
	}
}

function Get-PathCanonicalCase
{
	param( $path )

	$newPath = (Resolve-Path $path).Path
	$root = [System.IO.Path]::GetPathRoot( $newPath )
	if ( $newPath -ne $root ) # Handle root directory
		{ $newPath = [System.IO.Directory]::GetDirectories( $root, $newPath.Substring( $root.Length ) )[ 0 ] }
	$newPath
}
